Para resolver este filtro en la versi\'on en Assembler intentamos aprovechar al m\'{a}ximo los recursos dados por el lenguaje propio, como por ejemplo el uso
de m\'{a}scaras para separar en casos, en lugar de usar saltos condicionales. A continuaci\'on, presentamos una detallada descripci\'on del algoritmo implementado.


\subsection{Descripci\'on}

Este filtro divide los p\'ixeles en cuatro bandas, de acuerdo al valor de la siguiente f\'ormula:

\begin{figure}[H]
    \includegraphics[width=0.5\textwidth]{bandasFormula.png}
  \label{lolo}
\end{figure}

donde $b$ es la suma de las componentes red, green y blue del pixel.

\begin{codesnippet}
\begin{verbatim}
        sea s un puntero al principio de la imagen fuente
        sea d un puntero al principio de la imagen destino
        mientras s permanezca en la imagen
                leer 4 pixeles a partir de s, pi pi+1 pi+2 pi+3
                sumar los valores r, g y b para los cuatro pixeles
                asignar el valor predeterminado de acuerdo a la formula
                grabar los pixeles a partir de d
                d = d + 16
                s = s + 16
\end{verbatim}
\end{codesnippet}


Levantamos 4 p\'ixeles por acceso a memoria. Estos pixeles se encuentran alojados en $xmm0$.
Como debemos hacer sumas, necesitamos ``desempaquetar'' los datos para llevarlos a un tama\~no donde
podamos asegurarnos de no tener overflow's. Adem\'{a}s, tenemos el canal alfa que nos afectar\'{i}a la suma horizontal, que luego usaremos para obtener la
suma de los canales rojo, verde y azul. Entonces, mediante el uso de una m\'{a}scara que tenga ceros en las posiciones correspondientes al canal alfa y unos
en los otros tres canales, nos deshacemos del canal alfa.
Luego, creamos una copia de los p\'{i}xeles
en $xmm2$, y trabajamos con el registro $xmm3$ en cero, que usaremos para desempaquetar extendiendo, sin signo, la precisi\'{o}n. 
Desempaquetamos la parte baja de los datos almacenados en $xmm0$ como muestra la 
Figura \ref{unpackwb}. 

\begin{figure}[H]
    \includegraphics[width=0.7\textwidth]{unpackbw}
  \label{unpackwb}
  \caption{punpcklbw xmm0, xmm3}
\end{figure}

y procedemos de manera \'{a}naloga con la parte alta de $xmm2$.

A partir de esto, los datos son procesados en paralelo. Tanto en $xmm0$, como en $xmm2$, 
realizamos dos sumas horizontales consecutivas, obteniendo
as\'{i} los datos distribuidos de la siguente forma en $xmm0$:

\begin{center}  
   \begin{tabular}{| l | c | r | c | r | c | r | c | r |c | r |c | r |}
     \hline
     $r_0+g_0+b_0$& $r_1+g_1+b_1$ & $*$ & $*$ & $*$  & $*$ & $*$ & $*$  \\ \hline
   \end{tabular}
\end{center}

Operamos \'{a}nalogamente con el registro $xmm2$.

Luego, limpiamos la parte alta de ambos registros, y acomodamos la sumas en $xmm2$ de manera tal que, al realizar un
\verb|or| entre $xmm0$ y $xmm2$, el resultado sean las cuatro sumas acumuladas en la parte baja de $xmm0$. 
Luego, volvemos a desempaquetar la parte baja de $xmm0$, extendiendo nuevamente la precisi\'{o}n, obteniendo: 

\begin{center}  
   \begin{tabular}{| l | c | r | c | r ||}
     \hline
     $r_0+g_0+b_0$& $r_1+g_1+b_1$ & $r_2+g_2+b_2$ & $r_3+g_3+b_3$  \\ \hline
   \end{tabular}
\end{center}

Despu\'{e}s, mediante el uso de instrucciones de comparaci\'{o}n sobre el registro con las sumas
obtendremos 5 m\'{a}scaras, donde cada una indicar\'{a} qu\'{e} p\'{i}xeles cumplen con pertenecer a cada banda. Por ejemplo, tomando el caso de la segunda banda,
un registro as\'{i}: 

\begin{center}  
   \begin{tabular}{| l | c | r | c | r ||}
     \hline
     0xFF& $0x00$ & $0x00$ & 0xFF  \\ \hline
   \end{tabular}
\end{center}

indica que los p\'{i}xeles 0 y 3 cumplen con estar en la segunda banda, mientras que el 1 y el 2  no. Luego, si hacemos un \verb|pand| con un registro que tenga
el valor prefijado para dicha banda: 

\begin{center}  
   \begin{tabular}{| l | c | r | c | r |c | r | c | r | c | r | c | r | c | r | l|}
     \hline
     $64$& $64$ & $64$ & $0$ &$64$& $64$ & $64$ & $0$ &$64$& $64$ & $64$ & $0$&$64$& $64$ & $64$ & $0$\\ \hline
   \end{tabular}
\end{center}

tendremos procesados y listos para mover a la imagen destino los p\'{i}xeles 0 y 3. Si operamos de manera an\'{a}loga sobre los otros 4 registros que representan
las otras 4 bandas, tendremos procesados los 4 p\'{i}xeles que hemos leido, y de manera tal que nos permitir\'{a}n, mediante el uso de la instrucci\'on \verb|or| entre
los 5, tener ya procesados y listos para mover a la imagen destino los cuatro p\'{i}xeles. Luego, copiamos los datos en la imagen destino.

\subsection{Experimentaci\'on}

\subsubsection{Saltos condicionales}

En este experimento deseamos ver el impacto de los saltos condicionales en la performance del c\'odigo C. Para hacer esto, quitamos la l\'ogica encargada de detectar
la banda a la que pertence un p\'ixel, dejando una sola banda.

\begin{figure}[H]
    \includegraphics[width=0.8\textwidth]{bandas31}
  \label{bandas31}
\end{figure}

Resulta evidente en el gr\'afico que el impacto de los saltos condicionales es enorme, al punto que el programa tarda radicalmente menos en aplicar el filtro
sobre las im\'{a}genes. Partiendo de la informacion que se refleja en el grafico y en las clases teoricas, concluimos 
que esto se da porque, si dejamos una sola banda en la cual est\'an todos los p\'ixeles, este filtro funciona de manera similar
a cropflip, pues no es m\'as que una transferencia de un valor prefijado, el correspondiente a la \'unica banda, de una posici\'on de memoria a otra. Adem\'as,
sabemos que la presencia de saltos condicionales en el c\'odigo entorpece el funcionamiento del procesador. Esto sucede pues los saltos condicionales, potencialmente,
obligan a hacer un $flush$ en el pipeline, es decir, invalidar todas las etapas previas del pipeline.

Mencionamos, como aclaraci\'on, que el pipeline es una t\'ecnica que consiste en lo siguiente: separar cada instrucci\'on en una serie de pasos
de manera que se pueda ejecutar, de ser posible, varios pasos de instrucciones consecutivas en paralelo.
Pero si una de las instrucciones a ejecutar es 
un salto condicional a otro lugar del c\'odigo, y la condici\'on del salto resulta verdadera, potencialmente pueden invalidarse todos los opcodes decodificados,
todos los operandos tra\'idos de memoria y dem\'as etapas del pipeline. Esto es porque, en general, podemos saltar a cualquier lugar de la memoria, con lo que 
los opcodes y operandos no serian \'utiles/v\'alidos.

\subsubsection{Secuencial vs. Vectorial}

En este experimento seguimos con la idea de los experimentos 2.2.4 y 3.2.1, es decir, comprobar la utilidad de programar en un lenguaje de bajo nivel. Los datos
considerados son los que aparecen descriptos en las aclaraciones.  

\begin{figure}[H]
    \includegraphics[width=1\textwidth]{bandas14}
  \label{bandas14}
\end{figure}

En este gr\'afico se observa que las optimizaciones O2 y O3 superan la versi\'on en ASM, sin embargo, proporcionalmente hablando, la diferencia es mucho menor que 
en el experimento 3.2.1. La conclusi\'on a la que llegamos en este caso se basa fuertemente en las conclusiones de los experimentos 2.2.4 y 3.2.1 y en el hecho de que este filtro 
transfiere la informaci\'on en una cantidad optimizada, por esto nos referimos al hecho de que no trasladamos un byte cada vez, y ademas procesa los p\'ixeles en paralelo.
Siendo de esta forma, asumimos que el compilador esta optimizando el procesamiento de datos, como sucedi\'o en el experimento 3.2.1, mientras que realiza la transferencia de 
informaci\'on de manera m\'as lenta que la versi\'on que escribimos en ASM, lo que explica por qu\'e la diferencia entre performance no es tan grande como en el caso 3.2.1.

